package com.turbo.cloud.core.log;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 日志切面
 * @author zhangluning
 */
@Slf4j
@Order(1)
@Aspect
@Component
public class LogInterceptAspect {

    /**
     * 匹配所有Web、Web REST端点的切入点。
     */
    @Pointcut("( execution(* com.*..*(..)) && within(@org.springframework.web.bind.annotation.RestController *) || within(@org.springframework.stereotype.Controller *))")
    public void logIntercept() {
        // 方法是空的，因为这只是一个切入点，实现在advice中。
    }

    /**
     * 环绕通知
     * 1、@Around 的 value 属性：绑定通知的切入点表达式。可以关联切入点声明，也可以直接设置切入点表达式
     * 2、Object ProceedingJoinPoint.proceed(Object[] args) 方法：继续下一个通知或目标方法调用，返回处理结果，如果目标方法发生异常，则 proceed 会抛异常.
     * 3、假如目标方法是控制层接口，则本方法的异常捕获与否都不会影响目标方法的事务回滚
     * 4、假如目标方法是控制层接口，本方法 try-catch 了异常后没有继续往外抛，则全局异常处理 @RestControllerAdvice 中不会再触发
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("logIntercept()")
    public Object around(ProceedingJoinPoint joinPoint) {
        if (log.isDebugEnabled()) {
            log.debug("【环绕通知-开始】methodName={}", joinPoint.toLongString());
        }

        //方法的返回值
        Object result = null;
        try {
            result = joinPoint.proceed();

            if (log.isDebugEnabled()) {
                log.debug("【环绕通知-执行】result::{}", result);
            }
        } catch (Throwable e) {
            log.error("【环绕通知-执行】error::", e);
            throw new RuntimeException(e.getMessage());
        }

        if (log.isDebugEnabled()) {
            log.debug("【环绕通知-结束】methodName={}", joinPoint.toLongString());
        }

        return result;
    }
}
